package com.macaline.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class ZipUtils {
	public static void main(String[] args) throws IOException {
		String path = "/Users/a/GitHub/wangmarket/target/wangmarket/WEB-INF/view/plugin/formManage";
		dozip(path, "/Users/a/zip.zip");
	}
	/**
	 * 解压文件
	 * @author warm_joy
	 * @param srcFile 需要解压的文件
	 * @param destDirPath 解压到的目标路径
	 * @throws RuntimeException
	 */
	public static void unZip(File srcFile, String destDirPath) throws RuntimeException {
		long start = System.currentTimeMillis();
		// 判断源文件是否存在
		if (!srcFile.exists()) {
			throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
		}
		// 开始解压
		ZipFile zipFile = null;
		try {
			// 对文件进行压缩封装
			zipFile = new ZipFile(srcFile);
			Enumeration<? extends ZipEntry> entries = zipFile.entries();
			while (entries.hasMoreElements()) {
				ZipEntry entry = (ZipEntry) entries.nextElement();
				System.out.println("解压" + entry.getName());
				// 如果是文件夹，就创建个文件夹
                if (entry.isDirectory()) {
                    String dirPath = destDirPath + File.separator + entry.getName();
                    File dir = new File(dirPath);
                    dir.mkdirs();
                } else {
                    // 如果是文件，就先创建一个文件，然后用io流把内容copy过去
                    File targetFile = new File(destDirPath + File.separator + entry.getName());
                    // 保证这个文件的父文件夹必须要存在
                    if(!targetFile.getParentFile().exists()){
                        targetFile.getParentFile().mkdirs();
                    }
                    targetFile.createNewFile();
                    // 将压缩文件内容写入到这个文件中
                    InputStream is = zipFile.getInputStream(entry);
                    FileOutputStream fos = new FileOutputStream(targetFile);
                    int len;
                    byte[] buf = new byte[1024];
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    // 关流顺序，先打开的后关闭
                    fos.close();
                    is.close();
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("解压完成，耗时：" + (end - start) +" ms");
        } catch (Exception e) {
            throw new RuntimeException("unzip error from ZipUtils", e);
        } finally {
            if(zipFile != null){
                try {
                    zipFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
	
	/**
	 * 对文件进行压缩
	 * @author warm_joy
	 * @param srcfile 需要压缩的文件夹路径
	 * @param zipfile 压缩的目标文件夹
	 * @throws IOException
	 */
	public static void dozip(String srcfile, String zipfile) throws IOException {
		String temp = "";
		File src = new File(srcfile);
		File zipFile = new File(zipfile);
		// 判断要压缩的文件存不存在
		if (!src.exists()) {
			System.err.println("要压缩的文件不存在！");
			System.exit(1);
		}
		// 如果说压缩路径不存在，则创建
		if (!zipFile.getParentFile().exists()) {
			zipFile.getParentFile().mkdirs();
			// System.out.println("创建ok");
		}
		// 封装压缩的路径
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(zipfile));
		// 这里可以加入校验
		// CheckedOutputStream cos = new CheckedOutputStream(bos,new CRC32());
		// 还可以设置压缩格式，默认UTF-8
		Charset charset = Charset.forName("UTF-8");
		ZipOutputStream zos = new ZipOutputStream(bos, charset);
		zip(src, zos, temp);
		// 关闭流
		zos.flush();
		zos.close();
		System.out.println("压缩完成！");
		System.out.println("压缩文件的位置是：" + zipfile);
		// System.out.println("检验和："+cos.getChecksum().getValue());
	}

	/**
	 * 压缩文件夹
	 * @author warm_joy
	 * @param file 需要压缩的原文件夹
	 * @param zos 目标压缩文件的输出流
	 * @param temp 缓存文件文件使用的路径
	 * @throws IOException
	 */
	private static void zip(File file, ZipOutputStream zos, String temp) throws IOException {
		// 如果不加"/"将会作为文件处理，空文件夹不需要读写操作
		if (file.isDirectory()) {
			String str = temp + file.getName() + "/";
			zos.putNextEntry(new ZipEntry(str));
			File[] files = file.listFiles();
			for (File file2 : files) {
				zip(file2, zos, str);
			}
		} else {
			// System.out.println("当前文件的父路径："+temp);
			ZipFile(file, zos, temp);
		}
	}

	/**
	 * 将文件加入到压缩文件中
	 * @author warm_joy
	 * @param srcfile 需要加入压缩包的文件 
	 * @param zos 压缩文件的输出流
	 * @param temp 加入压缩文件中的文件夹目录
	 * @throws IOException
	 */
	private static void ZipFile(File srcfile, ZipOutputStream zos, String temp) throws IOException {
		// 默认的等级压缩-1
		// zos.setLevel(xxx);
		// 封装待压缩文件
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcfile));
		zos.putNextEntry(new ZipEntry(temp + srcfile.getName()));

		// 进行文件的写入
		byte buff[] = new byte[1024];
		int len;
		while ((len = bis.read(buff)) != -1) {
			zos.write(buff, 0, len);
		}
		// 按标准需要关闭当前条目，不写也行
		zos.closeEntry();
		bis.close();
	}
}
